//--- Projeto Domus
// interactionsource.com
// Koji Pereira, Andre Veloso e Marcos Paulo

/*
 Projeto Domus
 interactionsource.com
 Koji Pereira, Andre Veloso e Marcos Paulo

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

// Bolinha de malabares

//MMA7260QT 3-Axis Accelerometer
// Sampling rate - 350Hz eixos X e Y - 1 sample a cada 2.857ms
// 150Hz eixo Z - 1 sample a cada 6.66ms

//Nessa versao foi implementado um vermelho pulsante para 
//a posicao de repouso, o azul para movimento de subida e descida,
//o verde para aceleracao crescente 

/*

Orange  (RGB: 255, 127, 0)
Yellow  (RGB: 255, 255, 0)
Indigo  (RGB: 111, 0, 255)
Violet  (RGB: 143, 0, 255)

Red     (RGB: 255, 0,   0)
Green   (RGB: 0,   255, 0)
Blue    (RGB: 0,   0, 255)

 */

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif 

#define pinX 0   // Numero do pino onde se vai ligar o X do acelerometro
#define pinY 1   // Numero do pino onde se vai ligar o Y do acelerometro
#define pinZ 2   // Numero do pino onde se vai ligar o Z do acelerometro

int valX = 0; 
int valY = 0; 
int valZ = 0;

float tensaoX;
float tensaoY;
float tensaoZ;

float forcaX;
float forcaY;
float forcaZ;

float oldValX = 0; 
float oldValY = 0; 
float oldValZ = 0;

float diffX = 0;
float diffY = 0;
float diffZ = 0;

int LedR = 3;
int LedG = 5;
int LedB = 6;

unsigned char redVal;
unsigned char greenVal;
unsigned char blueVal;

int lastRedVal;
int lastGreenVal;
int lastBlueVal;

int red_min = 150;
int red_max = 255;

int blue_min = 185;
int blue_max = 255;

int green_min = 195;
int green_max = 255;

float h = 0;
float s = 1.0;
float v = 0.8;

float qtMovimentacao = 0;

float resultante;

float oldResultante;

float diffResultante;

int pulso = 0;
char sig_pulso = 0;

int cont_caindo = 0;
int cont_subindo = 0;
int cont_lento = 0;
int cont_transicao = 0;

void setup(){
  
        //cbi(ADMUX, REFS1); //clear REFS1 bit (0)
        //cbi(ADMUX, REFS0); //clear REFS0 bit (0)
  
	Serial.begin(57600);  // Output do serial com Baud Rate de 57600

        //Seta o valor de referencia do Arduino de acordo com o 
        //valor vindo do acelerometro na sua saida VCC +- 3.3V 
        
       
        analogReference(EXTERNAL);

        //pinMode(pinZ, INPUT);

	redVal = 255; 
	greenVal = 255; 
	blueVal = 255;

	lastRedVal = 255;
	lastGreenVal = 255;
	lastBlueVal = 255;

	update();
}

// This function updates the LED outputs.
void update() {
	analogWrite(LedR, redVal);
	analogWrite(LedG, greenVal);
	analogWrite(LedB, blueVal);
        
        delay(10);

}

void updateRGB(int r, int g, int b) {
	analogWrite(LedR, r);
	analogWrite(LedG, g);
	analogWrite(LedB, b);

	lastRedVal = r;
	lastGreenVal = g;
	lastBlueVal = b;

}


void color_random( float qtMov ) 
{
	qtMov = constrain(qtMov, 0, 9.0);

	h = h + (qtMov*10);

	if (h > 360.0)  h -= 360.0;


	if ((h > 0) && (h < 90 )) {

		//Orange  (RGB: 255, 127, 0)
		redVal = 0;
		greenVal = 240;
		blueVal = 255;

	} else if ((h > 90) && (h < 180 )) {

		//Yellow  (RGB: 255, 255, 0)
		redVal = 0;
		greenVal = 210;
		blueVal = 255;


	} else if ((h > 180) && (h < 270 )) {

		//Indigo  (RGB: 111, 0, 255)
		redVal = 144;
		greenVal = 255;
		blueVal = 20;


	} else if ((h > 270) && (h < 360 )) {

		//Violet  (RGB: 143, 0, 255)
		redVal = 112;
		greenVal = 255;
		blueVal = 20;

	}

	update();

}

// This function updates one of the color variables
// either getting brighter or getting dimmer.
// It also updates the outputs 
void color_transition( float qtMov )
{

	qtMov = constrain(qtMov, 0, 9.0);

	h = h + qtMov;

	if (h > 360.0)  h -= 360.0;

	hsv_to_rgb(h, s, v, &redVal, &greenVal, &blueVal);
	update();

}

void color_change(float fr, float fg, float fb) {

	if ( fr > 2.00 )  {
		lastRedVal =  map( constrain(fr, 0, 3.3), 0, 3.3, 0, 255 ); 

	}

	if ( fg > 2.00  )  {
		lastGreenVal = map( constrain(fg, 0, 3.3), 0, 3.3, 0, 255 ); 

	}

	if ( fb > 2.00 ) {
		lastBlueVal = map( constrain(fb, 0, 3.3), 0, 3.3, 0, 255 ); 

	}

	updateRGB(lastRedVal, lastGreenVal, lastBlueVal);
	delay(10);

}

void hsv_to_rgb(float h, float s, float v, 
		unsigned char *rc, unsigned char *gc, unsigned char *bc) {

	int h_i = ((int)(h/60)) % 6;

	float f = (h/60) - (int)(h/60);

	float r,g,b;

	float p = v * (1.0 - s);
	float q = v * (1.0 - f*s);
	float t = (1.0 - (1.0 - f)*s);

	switch(h_i) {
	case 0:  r = v; g = t; b = p; break;
	case 1:  r = q; g = v; b = p; break;
	case 2:  r = p; g = v; b = t; break;
	case 3:  r = p; g = q; b = v; break;
	case 4:  r = t; g = p; b = v; break;
	case 5:  r = v; g = p; b = q; break;
	}

	*rc = red_max - (char)((red_max - red_min)*r);
	*gc = green_max - (char)((green_max - green_min)*g);
	*bc = blue_max - (char)((blue_max - blue_min)*b);
}

void update_pulso() {

	if (pulso > 255) {
		sig_pulso = 1;
	} else if (pulso < 0) {
		sig_pulso = 0;
	}

	if (sig_pulso == 1) {
		pulso -=2;
	} else if (sig_pulso == 0) {
		pulso +=2;  
	}

}

void loop(){

	oldValX = forcaX;
	oldValY = forcaY;
	oldValZ = forcaZ;

	oldResultante = resultante;

	//Leitura Bruta dos valores de aceleracao do sensor
	valX = analogRead(pinX);    // Ler o pino X
	valY = analogRead(pinY);    // Ler o pino Y
	valZ = analogRead(pinZ);    // Ler o pino Z

	//tensaoX = map(valX, 0, 1023, 0, 255);
	//tensaoY = map(valY, 0, 1023, 0, 255);
	//tensaoZ = map(valZ, 0, 1023, 0, 255);

	//tensaoX = (tensaoX*1.65)/85;
	//tensaoY = (tensaoY*1.65)/85;
	//tensaoZ = (tensaoZ*1.65)/85;
        
        //Conversao do valor de entrada
        //A entrada analogicaa com conversor ADC de 10bits retorna valores
        //entre 0 e 1024. Esse valor eh regulado pelo pino AREF
        //valor de 0.003223V por input para AREF de 3.3V e 0.003135V 
        //por input para 3.21V

        tensaoX = valX * 0.003135;
	tensaoY = valY * 0.003135;
	tensaoZ = valZ * 0.003135;

	//calcula os valores de forca aplicados aos eixos
        //normalizando o valor para 0 a 1.5G, de acordo com 
        //a especificacao do sensor 
        //Nesse modelo o valor de 1G corresponde a 0.83
	forcaX = tensaoX-1.65;
	forcaY = tensaoY-1.65;
	forcaZ = tensaoZ-1.65;

	//Calcula a diferenca de aceleracao dos eiXos
	diffX = forcaX-oldValX;
	diffY = forcaY-oldValY;
	diffZ = forcaZ-oldValZ;

	if (diffX<0) diffX *= (-1);
	if (diffY<0) diffY *= (-1);
	if (diffZ<0) diffZ *= (-1);

	qtMovimentacao = diffX + diffY + diffZ;

	resultante = sqrt( sq(forcaX) + sq(forcaY) + sq(forcaZ) );

	//diffResultante = oldResultante - resultante;

	diffResultante = resultante - 0.83;

  /*
  //  DEBUG DA TENSAO DE ENTRADA - PARA AVALIAR A MONTAGEM
  //COM O USO DE UM MULTIMETRO
  Serial.print(" - tensaoX:");
  Serial.print( tensaoX );
  Serial.print(" tensaoY:");  
  Serial.print( tensaoY);
  Serial.print(" tensaoZ:");
  Serial.print( tensaoZ );
  */
  	 
  /*
  Serial.print(" - valX:");
  Serial.print( valX );
  Serial.print(" valY:");  
  Serial.print( valY);
  Serial.print(" valZ:");
  Serial.print( valZ );
  */
	
  Serial.print(" - forcaX:");
  Serial.print(forcaX);
  Serial.print(" forcaY:");  
  Serial.print(forcaY);
  Serial.print(" forcaZ:");
  Serial.print(forcaZ);
	 

	/*
  Serial.print(" - DiffX:");
  Serial.print(diffX);
  Serial.print(" DiffY:");  
  Serial.print(diffY);
  Serial.print(" DiffZ:");
  Serial.print(diffZ);
	 */

	//Serial.print(" - resultante: ");
	//Serial.print(resultante);

	Serial.print(" - diffResultante: ");
	Serial.print(diffResultante);

	//Serial.print(" - pulso: ");
	//Serial.print(pulso);


	if ( diffResultante > 1.3 ) {//cor verde


		//Estador de filtro
		cont_caindo = 0;
		cont_subindo++;
		cont_lento = 0;
		cont_transicao++;

		if (cont_subindo> 5) {
			updateRGB(255,0,255);
			
                        pulso = 255;
			Serial.print(" - ######## subindo  ");
			cont_transicao = 0;
		}

	} else if (( diffResultante < 1.3 ) && ( diffResultante >  0.20) ) { //colorido
		

		cont_subindo = 0;
		cont_caindo = 0;
		cont_lento = 0;
		cont_transicao++;

		if ( cont_transicao > 5 ) {
			//color_transition(qtMovimentacao);
			//color_random(qtMovimentacao);
			//updateRGB(255,255,constrain(pulso, 0, 255));
                        updateRGB(255,255,0);

			pulso = 255;

                        Serial.print(" - ### transicao ");
		} 

	} else if (( diffResultante < 0.20 ) && ( diffResultante >  -0.40) ) { //pulsando vermelho lento


		cont_subindo = 0;
		cont_caindo = 0;
		cont_lento++;
		cont_transicao++;

		if ( cont_lento > 10 ) {

			updateRGB(constrain(pulso, 0, 255),255,255);

			Serial.print(" - ### lento ");

			cont_transicao = 0;
		}


	} else if ( diffResultante < -0.40 ) { // azul sobe e desce

		//Estador de filtro
		cont_caindo++;
		cont_subindo = 0;
		cont_lento = 0;
		cont_transicao++;

		if (cont_caindo> 5) {
			updateRGB(255,255,0);
			pulso = 255;
			Serial.print(" - ############## caindo ");

			cont_transicao = 0;
		}
	} else {
		//comportamento default 
		//color_transition(qtMovimentacao);
	}


	update_pulso();

	Serial.println(" ");


}

